#include "socket.hpp"
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/uio.h>

using namespace event_framework;

int Socket::Sendmsg(const EndPoint& peer, const std::vector<std::pair<char*, int>>& bufvec)
{
    if (bufvec.empty()) return -1;
    
    struct msghdr msg;
    msg.msg_name = (void*)peer.GetAddrPtr();
    msg.msg_namelen = peer.GetAddrLen();
    msg.msg_control = 0;
    msg.msg_controllen = 0;
    msg.msg_flags = 0;
    msg.msg_iovlen = bufvec.size();
    struct iovec *iov = new struct iovec[bufvec.size()]; 
    msg.msg_iov = iov;
    size_t offset = 0;
    for (const auto& bufpair : bufvec)
    {
        iov[offset].iov_base = std::get<0>(bufpair);
        iov[offset].iov_len = std::get<1>(bufpair);
        offset++;
    }
    int ret = sendmsg(fd, &msg, 0);
    delete[] iov;
    return ret;
}
// for tcp
int Socket::Writev(const std::vector<std::pair<char*, int>>& bufvec)
{
    struct iovec *iov = new struct iovec[bufvec.size()];
    size_t offset = 0;
    for (const auto& bufpair : bufvec)
    {
        iov[offset].iov_base = std::get<0>(bufpair);
        iov[offset].iov_len = std::get<1>(bufpair);
        offset++;
    }
    int ret = writev(fd, iov, bufvec.size());
    delete[] iov;
    return ret;
}

int Socket::Recvmsg(const EndPoint& peer, std::vector<std::pair<char*, int>>& bufvec)
{
    if (bufvec.empty()) return -1;
    
    struct msghdr msg;
    msg.msg_name = (void*)peer.GetAddrPtr();
    msg.msg_namelen = peer.GetAddrLen();
    msg.msg_control = 0;
    msg.msg_controllen = 0;
    msg.msg_flags = 0;
    msg.msg_iovlen = bufvec.size();
    struct iovec *iov = new struct iovec[bufvec.size()]; 
    msg.msg_iov = iov;
    size_t offset = 0;
    for (const auto& bufpair : bufvec)
    {
        iov[offset].iov_base = std::get<0>(bufpair);
        iov[offset].iov_len = std::get<1>(bufpair);
        offset++;
    }
    int ret = recvmsg(fd, &msg, 0);
    delete[] iov;
    return ret;
}
// for tcp
int Socket::Readv(std::vector<std::pair<char*, int>>& bufvec)
{
    struct iovec *iov = new struct iovec[bufvec.size()];
    size_t offset = 0;
    for (const auto& bufpair : bufvec)
    {
        iov[offset].iov_base = std::get<0>(bufpair);
        iov[offset].iov_len = std::get<1>(bufpair);
        offset++;
    }
    int ret = readv(fd, iov, bufvec.size());
    delete[] iov;
    return ret;
}
void Socket::Close()
{
    if (fd < 0)
    {
        close(fd);
        fd = -1;
    }
}